package com.iwhalecloud.citybrain.flow.platform.manager.application.ConvertUtil;

import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.ParseRenderedVariable;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.SpringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ConstanceVariable;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpProcessInstanceHandleRelDto;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.HandleStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.HandleTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.ReadOperateTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowFormExternalInfoDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowProcessInstanceTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.ModelCustomConfigDomain;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.app.FlowApp;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.form.FormProcessInstanceHandleRelDto;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.UserInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
　　* @description: 流程实例中处理人的关系转换工具类
　　* @author shenrm
　　* @date 2021/10/20 9:58
　　*/

@Component
public class FormProcessInstanceHandleRelConvertUtil {


    public FormProcessInstanceHandleRelConvertUtil(){}


    /**
     * 流程实例与处理关系信息之间的对象转换
     *
     * @param processInstanceId
     * @param paramMap
     * @param workItemId
     * @param readOperateType
     * @return
     */
    public static List<FormProcessInstanceHandleRelDto> convertToProcessInstanceHandleRelDto(String processInstanceId, Map<String, Object> paramMap,
                                                                                             Map<String, String> map, String workItemId, String readOperateType) {
        Object obj = paramMap.get("flowReadCopyTo");
        if(Objects.isNull(obj)) {
            return Collections.emptyList();
        }

        // 获取流程或任务阅办人ID集合
        List<String> flowReadCopyToList = (List<String>) paramMap.get("flowReadCopyTo");
        String readDoJumpUrl = Optional.ofNullable(map.get("readDoJumpUrl")).orElse("");
        String sourceAppCode = Optional.ofNullable(map.get("sourceAppCode")).orElse("");
        String participantId = Optional.ofNullable(map.get("participantId")).orElse("");
        String participantName = Optional.ofNullable(map.get("participantName")).orElse("");

        // 循环组装
        FormProcessInstanceHandleRelDto handleRelDto;
        if (CollectionUtils.isNotEmpty(flowReadCopyToList)) {
            List<FormProcessInstanceHandleRelDto> handleRelDtoList = new ArrayList<FormProcessInstanceHandleRelDto>(flowReadCopyToList.size());
            String jumpConnection = getJumpConnection(processInstanceId, paramMap, workItemId, readDoJumpUrl);
            // 根据userId查询人员信息,转换成用户名称
            if(StringUtils.isEmpty(participantName) && StringUtils.isNotEmpty(participantId)) {
                UserInfo userInfo = SpringUtils.getBean(UserService.class).getUserInfoObj(participantId);
                participantName = userInfo == null ? "" : userInfo.getUserName();
            }
            for (String handlerId : flowReadCopyToList) {
                handleRelDto = new FormProcessInstanceHandleRelDto();
                // 设置流程实例ID
                handleRelDto.setProcessInstanceId(processInstanceId);
                // 处理人ID
                handleRelDto.setHandlerId(handlerId);
                // 任务实例ID
                handleRelDto.setTaskId(workItemId);
                handleRelDto.setSendUserCode(participantId);
                handleRelDto.setSendUserName(participantName);

                // 判断操作类型
                if (ReadOperateTypeEnum.STARTPROCESSINSTANCE.getCode().equals(readOperateType)) {
                    // 设置处理类型,这里是流程阅办类型
                    handleRelDto.setHandleType(HandleTypeEnum.READCOPYTO.getCode());
                } else if (ReadOperateTypeEnum.COMPLETEWORKITEM.getCode().equals(readOperateType)) {
                    // 设置处理类型,这里是任务阅办类型
                    handleRelDto.setHandleType(HandleTypeEnum.READTASK.getCode());
                }
                // 设置默认状态,未读
                handleRelDto.setStatus(HandleStatusEnum.NOREAD.getCode());
                // 获取用户任务外置表单跳转url,新增时多拼接一个状态,默认状态是未读
                handleRelDto.setJumpUrl(jumpConnection+"&status="+ HandleStatusEnum.NOREAD.getCode());

                // 设置来源应用编码
                handleRelDto.setSourceAppCode(sourceAppCode);

                // 需要根据流程实例ID获取对应配置业务appCode传给待办组件查询区分业务使用
                List<FlowApp> flowApps = SpringUtils.getBean(FlowAppRepository.class).getAppInfoByProcessInstanceId(processInstanceId);
                if(CollectionUtils.isNotEmpty(flowApps)) {
                    FlowApp flowApp = flowApps.get(0);
                    // 设置来源业务编码
                    handleRelDto.setBusinessCode(flowApp.getAppCode());
                }

                // 业务模块编码(业务侧发起传的)
                String businessModuleCodeVar = Optional.ofNullable(paramMap.get(ConstanceVariable.BUSINESS_MODULE_CODE)).map(Object::toString).orElse("");
                if(StringUtils.isNotBlank(businessModuleCodeVar)) {
                    handleRelDto.setBusinessModuleCode(businessModuleCodeVar);
                }

                // 表单模块编码(业务侧发起传的)
                String formModuleCodeVar = Optional.ofNullable(paramMap.get(ConstanceVariable.FORM_MODULE_CODE)).map(Object::toString).orElse("");
                if(StringUtils.isNotBlank(formModuleCodeVar)) {
                    handleRelDto.setFormModuleCode(formModuleCodeVar);
                }

                // 添加到集合中
                handleRelDtoList.add(handleRelDto);
            }
            return handleRelDtoList;
        }
        return null;
    }

    private static String getJumpConnection(String processInstanceId, Map<String, Object> paramMap, String workItemId, String readDoJumpUrl) {
        FlowProcessInstanceTraceRepository flowProcessInstanceTraceRepository = SpringUtils.getBean(FlowProcessInstanceTraceRepository.class);
        FlowTaskTraceRepository flowTaskTraceRepository = SpringUtils.getBean(FlowTaskTraceRepository.class);
        // 为空时取默认
        String defaultUrl = readDoJumpUrl.replace(":processInstanceId", processInstanceId).replace(":taskId", workItemId);

        String url = null;
        FlowProcessInstanceTraceVo processInstanceTrace = flowProcessInstanceTraceRepository.getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        FlowTaskTraceVo flowTaskTrace = flowTaskTraceRepository.getTaskTraceByTaskId(workItemId);
        String processDefinitionId = processInstanceTrace.getProcessDefinitionId();
        String deployId = SpringUtils.getBean(RepositoryService.class).createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult().getDeploymentId();

        List<ModelCustomConfigDomain> modelCustomConfigDomainList = SpringUtils.getBean(FlowReModelCustomConfigRepository.class).listModelConfigByDeployIdAndType(deployId
                , flowTaskTrace.getActivityId(), ConstanceVariable.EXTERNAL_FORM_SHOW_STYLE);
        if (modelCustomConfigDomainList != null && !modelCustomConfigDomainList.isEmpty()) {
            String showType = modelCustomConfigDomainList.get(0).getConfig();
            if (Objects.equals(showType, "empty")) {
                String formkey = flowTaskTrace.getFormKey();
                FlowFormExternalInfoDomain flowFormExternalInfoDomain = SpringUtils.getBean(FlowFormRepository.class).findExternalFormInfo(formkey);
                if (Objects.nonNull(flowFormExternalInfoDomain)) {
                    String formUrl = flowFormExternalInfoDomain.getFormUrl();
                    url = ParseRenderedVariable.parseRenderedVariable(formUrl, paramMap);
                }
            }
        }
        // 外置表单跳转链接是空就取默认配置
        return url == null ? defaultUrl : url;
    }


    /**
     * 流程实例或任务实例与处理关系信息之间的对象转换
     *
     * @param processInstanceHandleRelDto
     * @param readCopyTos
     * @return
     */
    public static List<FormProcessInstanceHandleRelDto> convertToRequestDtoList(HttpProcessInstanceHandleRelDto processInstanceHandleRelDto, List<String> readCopyTos) {
        // 流程实例ID
        String processInstanceId = processInstanceHandleRelDto.getProcessInstanceId();
        // 任务实例ID
        String taskId = processInstanceHandleRelDto.getTaskId();
        // 发送阅办消息人ID
        String sendUserCode = processInstanceHandleRelDto.getSendUserCode();
        // 发送阅办消息人名称
        String sendUserName = processInstanceHandleRelDto.getSendUserName();
        // 应完成时间
        Date shouldCompleteTime = processInstanceHandleRelDto.getShouldCompleteTime();

        // 封装需要批量处理的数据
        List<FormProcessInstanceHandleRelDto> handleRelDtoList = new ArrayList<FormProcessInstanceHandleRelDto>();

        // 如果流程实例ID不为空并且任务实例ID为空,则只设置流程实例ID
        if(StringUtils.isNotBlank(processInstanceId) && StringUtils.isBlank(taskId)) {
            convertProcessInstanceToHandleList(readCopyTos, processInstanceId, handleRelDtoList,
                    sendUserCode, sendUserName, shouldCompleteTime);
        } else if(StringUtils.isBlank(processInstanceId) && StringUtils.isNotBlank(taskId)) { // 如果流程实例ID为空并且任务实例ID不为空,则只设置任务实例ID
            convertTaskInstanceToHandleList(readCopyTos, taskId, handleRelDtoList,
                    sendUserCode, sendUserName, shouldCompleteTime);
        } else if(StringUtils.isNotBlank(processInstanceId) && StringUtils.isNotBlank(taskId)){ // 两者都不为空时,分别组装
            convertProInsAndTaskToHandleList(readCopyTos, processInstanceId, taskId, handleRelDtoList,
                    sendUserCode, sendUserName, shouldCompleteTime);
        }
        return handleRelDtoList;
    }


    /**
     * 转换流程实例添加到集合中
     *
     * @param readCopyTos
     * @param processInstanceId
     * @param handleRelDtoList
     * @param sendUserCode
     * @param sendUserName
     * @param shouldCompleteTime
     */
    private static void convertProcessInstanceToHandleList(List<String> readCopyTos, String processInstanceId,
                                                           List<FormProcessInstanceHandleRelDto> handleRelDtoList, String sendUserCode,
                                                           String sendUserName, Date shouldCompleteTime) {
        if(CollectionUtils.isEmpty(readCopyTos)) {
            return;
        }

        // 处理人ID集合
        for (String readCopyTo : readCopyTos) {
            FormProcessInstanceHandleRelDto handleRelDto = new FormProcessInstanceHandleRelDto();
            // 设置流程实例ID
            handleRelDto.setProcessInstanceId(processInstanceId);

            // 设置抄送的阅办人
            handleRelDto.setHandlerId(readCopyTo);

            // 发送阅办消息人ID
            handleRelDto.setSendUserCode(sendUserCode);

            // 发送阅办消息人名称
            handleRelDto.setSendUserName(sendUserName);

            // 应完成时间
            handleRelDto.setShouldCompleteTime(shouldCompleteTime);

            // 设置处理类型,这里是流程阅办类型
            handleRelDto.setHandleType(HandleTypeEnum.READCOPYTO.getCode());

            // 设置默认状态,未读
            handleRelDto.setStatus(HandleStatusEnum.NOREAD.getCode());

            // 添加到集合中
            handleRelDtoList.add(handleRelDto);
        }
    }

    /**
     * 转换任务实例添加到集合中
     *
     * @param readCopyTos
     * @param taskId
     * @param handleRelDtoList
     * @param sendUserCode
     * @param sendUserName
     * @param shouldCompleteTime
     */
    private static void convertTaskInstanceToHandleList(List<String> readCopyTos, String taskId,
                                                        List<FormProcessInstanceHandleRelDto> handleRelDtoList, String sendUserCode,
                                                        String sendUserName, Date shouldCompleteTime) {
        if(CollectionUtils.isEmpty(readCopyTos)) {
            return;
        }

        // 处理人ID集合
        for (String readCopyTo : readCopyTos) {
            FormProcessInstanceHandleRelDto handleRelDto = new FormProcessInstanceHandleRelDto();

            // 任务实例ID
            handleRelDto.setTaskId(taskId);

            // 设置抄送的阅办人
            handleRelDto.setHandlerId(readCopyTo);

            // 发送阅办消息人ID
            handleRelDto.setSendUserCode(sendUserCode);

            // 发送阅办消息人名称
            handleRelDto.setSendUserName(sendUserName);

            // 应完成时间
            handleRelDto.setShouldCompleteTime(shouldCompleteTime);

            // 设置处理类型,这里是流程阅办类型
            handleRelDto.setHandleType(HandleTypeEnum.READTASK.getCode());

            // 设置默认状态,未读
            handleRelDto.setStatus(HandleStatusEnum.NOREAD.getCode());

            // 添加到集合中
            handleRelDtoList.add(handleRelDto);
        }
    }

    /**
     *
     * @param readCopyTos
     * @param processInstanceId
     * @param taskId
     * @param handleRelDtoList
     * @param sendUserCode
     * @param sendUserName
     * @param shouldCompleteTime
     */
    private static void convertProInsAndTaskToHandleList(List<String> readCopyTos, String processInstanceId,
                                                         String taskId, List<FormProcessInstanceHandleRelDto> handleRelDtoList,
                                                         String sendUserCode, String sendUserName, Date shouldCompleteTime) {
        if(CollectionUtils.isEmpty(readCopyTos)) {
            return;
        }

        // 处理人ID集合
        for (String readCopyTo : readCopyTos) {
            FormProcessInstanceHandleRelDto handleRelDto = new FormProcessInstanceHandleRelDto();
            // 设置流程实例ID
            handleRelDto.setProcessInstanceId(processInstanceId);

            // 任务实例ID
            handleRelDto.setTaskId(taskId);

            // 设置抄送的阅办人
            handleRelDto.setHandlerId(readCopyTo);

            // 发送阅办消息人ID
            handleRelDto.setSendUserCode(sendUserCode);

            // 发送阅办消息人名称
            handleRelDto.setSendUserName(sendUserName);

            // 应完成时间
            handleRelDto.setShouldCompleteTime(shouldCompleteTime);

            // 设置处理类型,这里是流程阅办类型
            handleRelDto.setHandleType(HandleTypeEnum.READTASK.getCode());

            // 设置默认状态,未读
            handleRelDto.setStatus(HandleStatusEnum.NOREAD.getCode());

            // 添加到集合中
            handleRelDtoList.add(handleRelDto);
        }
    }
}
